module type Ring = sig
  type t
  val zero  : t
  val one   : t
  val (+)   : t -> t -> t
  val (~-)  : t -> t
  val ( * ) : t -> t -> t
  val to_string : t -> string
  val of_int : int -> t
end

module type Field = sig
  include Ring
  val (/) : t -> t -> t
end

module IntRing : (Ring with type t = int) = struct
  type t = int
  let zero = 0
  let one = 1
  let (+) = (+)
  let (~-) = (~-)
  let ( * ) = ( * )
  let to_string = string_of_int
  let of_int n = n
end

module IntField : Field = struct
  include IntRing
  let (/) = (/)
end

module FloatRing : (Ring with type t = float) = struct
  type t = float
  let zero = 0.
  let one = 1.
  let (+) = (+.)
  let (~-) = (~-.)
  let ( * ) = ( *. )
  let to_string = string_of_float
  let of_int n = float_of_int n
end

module FloatField : Field = struct
  include FloatRing
  let (/) = (/.)
end

module MakeRational(T: Field): Field = struct
  type t = T.t * T.t
  let zero = (T.zero, T.zero)
  let one = (T.one, T.one)
  let (+) (a, b) (c, d) = T.(a * d + c * b, b * d)
  let (~-) (a, b) = T.(-a, b)
  let (/) (a, b) (c, d) = T.(a/d, b/c)
  let ( * ) (a, b) (c, d) = T.(a*c, b*d)
  let to_string (a, b) = T.(to_string a ^ "/" ^ to_string b)
  let of_int n = T.(of_int n, one)
end

module IntRational = MakeRational(IntField)

module FloatRational = MakeRational(FloatField)
